import edu.princeton.cs.introcs.Out;
import edu.princeton.cs.introcs.StdOut;
import org.apache.commons.io.FilenameUtils;
import org.biojava3.alignment.Alignments;
import org.biojava3.alignment.template.Profile;
import org.biojava3.core.sequence.DNASequence;
import org.biojava3.core.sequence.ProteinSequence;
import org.biojava3.core.sequence.RNASequence;
import org.biojava3.core.sequence.compound.AminoAcidCompound;
import org.biojava3.core.sequence.io.FastaReaderHelper;
import org.biojava3.core.sequence.io.GenbankReaderHelper;
import org.biojava3.core.util.ConcurrencyTools;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;


public class Main {

    public static void main(String[] args) throws Exception {
        ParamParser params = new ParamParser(args);
        if (!params.state) {
            return;
        }

        List<ProteinSequence> proteinList = new ArrayList<ProteinSequence>();

        // Read DNA sequences from files and receive protein sequences
        for (String filename : params.inputFileArr) {
            StdOut.printf("File: %s\n\n", filename);
            LinkedHashMap<String, DNASequence> seqMap = readSeqFromFile(filename);
            for (DNASequence dna : seqMap.values()) {
                StdOut.println(dna.getOriginalHeader());
                StdOut.printf("GC content: %f%%\n", getGCContent(dna));
                StdOut.println("DNA:");
                StdOut.println(dna.getSequenceAsString());
                StdOut.println("RNA:");
                RNASequence rna = dna.getRNASequence();
                StdOut.println(rna.getSequenceAsString());
                StdOut.println("Protein:");
                ProteinSequence protein = rna.getProteinSequence();
                protein.setAccession(dna.getAccession());
                proteinList.add(protein);
                StdOut.println(protein.getSequenceAsString());
                StdOut.printf("\n\n");
            }
            StdOut.printf("-----------------------------\n\n");
        }

        // Multiple protein sequences alignment
        StdOut.println("Multiple protein sequences alignment");
        if (proteinList.size() < 2) {
            StdOut.println("At least 2 sequences must be provided for multiple alignment");
        } else {
            // MSA uses BLOSUM62 matrix by default, so we need no specific settings
            Profile<ProteinSequence, AminoAcidCompound> profile = Alignments.getMultipleSequenceAlignment(proteinList);
            ConcurrencyTools.shutdown();
            StdOut.println(profile.toString(Profile.StringFormat.CLUSTALW));
            Out out = new Out(params.outputFile);
            out.println(profile.toString(Profile.StringFormat.CLUSTALW));
            out.close();
        }
    }

    public static LinkedHashMap<String, DNASequence> readSeqFromFile(String filename) throws Exception {
        String ext = FilenameUtils.getExtension(filename);
        if (".fasta .fna .fa".contains('.' + ext)) {
            return FastaReaderHelper.readFastaDNASequence(new File(filename));
        } else if (".gb .gbk .gen .genbank".contains('.' + ext)) {
            return GenbankReaderHelper.readGenbankDNASequence(new File(filename));
        } else {
            throw new Exception("Unsupported file extension: " + ext);
        }
    }

    public static double getGCContent(DNASequence dna) {
        return dna.getGCCount() * 100.0 / dna.getLength();
    }
}
